/**
 * 单个商品数据
 */
class Goods {
    /**
     * 获取商品总价
     */
    get totalPrice() {
        return this.data.price * this.choose
    }
    /**
     * 是否选了该商品
     */
    get isChoose() {
        return this.choose > 0
    }
    constructor(g) {
        g = { ...g }
        Object.freeze(g) // 冻结对象，防止修改
        // 设置对象属性描述符
        Object.defineProperty(this, 'data', {
            configurable: false,
            get: function () {
                return g
            },
            set: function (v) {
                throw new Error(`属性data不可以修改`)
            }
        })
        var internalChoose = 0
        Object.defineProperty(this, 'choose', {
            configurable: false,
            get: function () {
                return internalChoose
            },
            set: function (v) {
                if (typeof v !== 'number') {
                    throw new Error(`属性choose必须是数字`)
                }
                if (v !== ~~v) {
                    throw new Error(`属性choose必须是整数`)
                }
                internalChoose = Math.max(0, v)
            }
        })

        Object.seal(this) // 封闭对象，防止新增属性
    }
    /**
     * 增加选择的数量
     */
    increase() {
        this.choose++
    }
    /**
     * 减少选择的数量
     */
    decrease() {
        if (this.choose > 0)
            this.choose--
    }
}
Object.freeze(Goods.prototype) // 冻结原型，防止修改

/**
 * 页面所有数据
 */
class UIData {
    constructor() {
        let pageGoods = []
        goodsData.forEach(g => {
            pageGoods.push(new Goods(g))
        })
        this.goods = pageGoods
        this.deliveryThreshold = 30 // 起送价
        this.deliveryPrice = 5 // 配送费
    }
    /**
     * 获取选中的商品数量
     * @returns {number}
     */
    getTotalChoose() {
        return this.goods.reduce((total, g) => {
            total += g.choose
            return total
        }, 0)
    }
    /**
     * 获取选中的商品总价
     * @returns {number}
     */
    getTotalPrice() {
        return this.goods.reduce((total, g) => {
            total += g.totalPrice
            return total
        }, 0)
    }
    /**
     * 增加某件商品选择的数量
     */
    increase(index) {
        this.goods[index].increase()
    }
    /**
     * 减少某件商品选择的数量
     */
    decrease(index) {
        this.goods[index].decrease()
    }
    /**
     * 是否选了某件商品
     * @returns {boolean}
     */
    isChoose(index) {
        return this.goods[index].isChoose
    }
    /**
     * 购物车是否有商品
     * @returns {boolean}
     */
    hasGoodsInCart() {
        return this.getTotalChoose() > 0
    }
    /**
     * 是否可以结算
     * @returns {boolean}
     */
    isCanCalculate() {
        return this.getTotalPrice() >= this.deliveryThreshold
    }
}

/**
 * 页面操作
 */
class UI {
    constructor() {
        this.uiData = new UIData()
        this.doms = {
            categoryList: document.querySelector('.category-list'),
            goodsList: document.querySelector('.goods-list'),

            footerCart: document.querySelector('.footer-cart'),
            footerCartCount: document.querySelector('.footer-cart-count'),
            footerBtn: document.querySelector('.footer-btn'),
            totalPrice: document.querySelector('.footer-totals-value span'),
            deliveryPrice: document.querySelector('.footer-totals-fee span'),
            threshold: document.querySelector('.footer-btn .threshold span'),
        }
        let cart = this.doms.footerCart.getBoundingClientRect()
        this.jumpTarget = {
            x: cart.left + cart.width / 2,
            y: cart.top + cart.height / 5
        }
        this.initCategoryEl()
        this.initGoodsEl()
        this.initEvent()
        this.updateFooter()
    }
    /**
     * 初始化类别
     */
    initCategoryEl() {
        let frag = document.createDocumentFragment()
        categoryData.forEach((item, index) => {
            let li = document.createElement('li')
            li.classList.add('category-item')
            li.textContent = item.name
            if (index == 0) {
                li.classList.add('active')
            }
            frag.appendChild(li)
        })
        this.doms.categoryList.appendChild(frag)
    }
    /**
     * 初始化商品
     */
    initGoodsEl() {
        let frag = document.createDocumentFragment()
        this.uiData.goods.forEach((item, index) => {
            let data = item.data;
            let div = document.createElement('div')
            div.classList.add('goods-item')
            div.dataset.index = index
            div.innerHTML = `
            <img class="goods-img" src="${data.pic}" alt="">
            <div class="goods-info">
                <div class="goods-name">${data.title}</div>
                <div class="goods-desc">${data.desc}</div>
                <div class="goods-row">
                    <div class="goods-sales">月售 ${data.sales}</div>
                    <div class="goods-favor">好评率 ${data.favorRate}%</div>
                </div>
                <div class="goods-confirm">
                    <div class="goods-price"><span>￥</span>${data.price}</div>
                    <div class="goods-btn">
                        <i class="goods-sub iconfont icon-jian"></i>
                        <div class="goods-num">${item.choose}</div>
                        <i class="goods-add iconfont icon-jia"></i>
                    </div>
                </div>
            </div>
            `
            frag.appendChild(div)
        })
        this.doms.goodsList.appendChild(frag)
    }

    /**
     * 初始化事件
     */
    initEvent() {
        // 动画结束
        this.doms.footerCart.addEventListener('animationend', function () {
            this.classList.remove('animate')
        })
        this.doms.goodsList.addEventListener('click', (e) => {
            let target = e.target
            if (target.classList.contains('goods-add')) {
                let index = target.closest('.goods-item').dataset.index
                this.increase(+index)
            } else if (target.classList.contains('goods-sub')) {
                let index = target.closest('.goods-item').dataset.index
                this.decrease(+index)
            }
        })
    }

    increase(index) {
        this.uiData.increase(index)
        this.updateGoodsItem(index)
        this.jumpToCart(index)
    }
    decrease(index) {
        this.uiData.decrease(index)
        this.updateGoodsItem(index)
        this.updateFooter()
    }
    /**
     * 更新某个元素的显示状态
     * @param {*} index 
     */
    updateGoodsItem(index) {
        var goodDom = this.doms.goodsList.children[index]
        if (this.uiData.isChoose(index)) {
            goodDom.classList.add('choose')
        } else {
            goodDom.classList.remove('choose')
        }
        goodDom.querySelector('.goods-num').textContent = this.uiData.goods[index].choose

    }
    /**
     * 更新页脚
     */
    updateFooter() {
        let total = this.uiData.getTotalPrice()
        this.doms.totalPrice.textContent = total.toFixed(2)
        this.doms.deliveryPrice.textContent = this.uiData.deliveryPrice;
        this.doms.threshold.textContent = this.uiData.deliveryThreshold;
        if (this.uiData.isCanCalculate()) {
            this.doms.footerBtn.classList.add('calculate')
        } else {
            this.doms.footerBtn.classList.remove('calculate')
            let nums = (this.uiData.deliveryThreshold - total).toFixed(2)
            this.doms.threshold.textContent = nums
        }

        if (this.uiData.hasGoodsInCart()) {
            this.doms.footerCart.classList.add('active')
            this.doms.footerCartCount.textContent = this.uiData.getTotalChoose()
        } else {
            this.doms.footerCart.classList.remove('active')
        }
    }
    /**
     * 添加购物车动画
     */
    addCartAnimate() {
        this.doms.footerCart.classList.add('animate')
    }
    /**
     * 跳到购物车
     */
    jumpToCart(index) {
        let btnAdd = this.doms.goodsList.children[index].querySelector('.goods-add')
        let rect = btnAdd.getBoundingClientRect()
        let start = {
            x: rect.left,
            y: rect.top
        }

        // 创建跳跃元素
        let div = document.createElement('div')
        div.className = 'add-to-cart'
        let i = document.createElement('i')
        i.className = 'iconfont icon-jia'
        // 初始化位置
        div.style.transform = `translateX(${start.x}px)`
        i.style.transform = `translateY(${start.y}px)`
        div.appendChild(i)
        document.body.appendChild(div)

        requestAnimationFrame(() => {
            // 跳跃到目标位置
            div.style.transform = `translateX(${this.jumpTarget.x}px)`
            i.style.transform = `translateY(${this.jumpTarget.y}px)`
        })

        // css 过渡结束
        div.addEventListener('transitionend', () => {
            div.remove()
            this.addCartAnimate()
            this.updateFooter()
        },
            { once: true }//事件只触发一次
        )
    }

}

const ui = new UI()